package com.zoe.onelink.ratelimit.autoconfigure;

import com.alibaba.csp.sentinel.SphO;
import com.google.common.util.concurrent.RateLimiter;
import com.zoe.onelink.ratelimit.aspect.ApiRateLimitAspect;
import com.zoe.onelink.ratelimit.property.OnelinkRateLimitProperties;
import com.zoe.onelink.ratelimit.rule.init.RateLimitRuleInit;
import com.zoe.onelink.ratelimit.rule.register.RateLimitRuleRegister;
import com.zoe.onelink.ratelimit.rule.register.impl.GuavaRateLimitRuleRegister;
import com.zoe.onelink.ratelimit.rule.register.impl.SentinelRateLimitRuleRegister;
import com.zoe.onelink.ratelimit.sepc.ApiRateLimiter;
import com.zoe.onelink.ratelimit.sepc.impl.GuavaApiRateLimiter;
import com.zoe.onelink.ratelimit.sepc.impl.SentinelApiRateLimiter;
import com.zoe.onelink.ratelimit.sepc.model.DefaultRateLimitFailureResultProvider;
import com.zoe.onelink.ratelimit.sepc.model.RateLimitFailureResultProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-12-05
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OnelinkRateLimitProperties.class)
@ConditionalOnProperty(prefix = OnelinkRateLimitProperties.PREFIX, name = "enabled", matchIfMissing = true)
public class OnelinkRateLimitAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public RateLimitFailureResultProvider rateLimitResultProvider() {
        return new DefaultRateLimitFailureResultProvider();
    }

    @Bean
    @ConditionalOnBean(RateLimitRuleRegister.class)
    public RateLimitRuleInit rateLimitRuleInit(ApplicationContext applicationContext,
                                               RateLimitRuleRegister rateLimitRuleRegister) {
        return new RateLimitRuleInit(applicationContext, rateLimitRuleRegister);
    }

    @Bean
    @ConditionalOnBean(ApiRateLimiter.class)
    public ApiRateLimitAspect apiRateLimitAspect(ApiRateLimiter apiRateLimiter,
                                                 RateLimitFailureResultProvider rateLimitFailureResultProvider) {
        log.info("[OneLinkFrm] 开启限流模块: {}", apiRateLimiter.getClass().getSimpleName());
        return new ApiRateLimitAspect(apiRateLimiter, rateLimitFailureResultProvider);
    }

    @SuppressWarnings("UnstableApiUsage")
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(RateLimiter.class)
    @ConditionalOnProperty(prefix = OnelinkRateLimitProperties.PREFIX, name = "module", havingValue = "guava", matchIfMissing = true)
    static class GuavaRateLimitAutoConfiguration {

        @Bean
        public GuavaApiRateLimiter guavaApiRateLimiter() {
            return new GuavaApiRateLimiter();
        }

        @Bean
        public RateLimitRuleRegister guavaRateLimitRuleRegister(GuavaApiRateLimiter guavaApiRateLimiter) {
            return new GuavaRateLimitRuleRegister(guavaApiRateLimiter);
        }
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(SphO.class)
    @ConditionalOnProperty(prefix = OnelinkRateLimitProperties.PREFIX, name = "module", havingValue = "sentinel")
    static class SentinelRateLimitAutoConfiguration {

        @Bean
        public SentinelApiRateLimiter sentinelApiRateLimit() {
            return new SentinelApiRateLimiter();
        }

        @Bean
        public RateLimitRuleRegister sentinelRateLimitRuleRegister() {
            return new SentinelRateLimitRuleRegister();
        }

    }

}
